home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 May: Tool Chest / Dev.CD May 98 TC.toast / Tool Chest / Localization / FMAT Editor / FMAT Editor 1.0.1 sources / Source / FMAT Editor.c next >
Encoding:
C/C++ Source or Header  |  1993-11-08  |  23.8 KB  |  881 lines  |  [TEXT/KAHL]

  1. #include <GestaltEqu.h>
  2. #include "FMAT.h"
  3.  
  4. /*
  5. File ResFMATEd.c
  6. by Michael Hecht (Michael_Hecht@mac.sas.com)
  7. July 14, 1993
  8.  
  9. based on material
  10.     Copyright Apple Computer, Inc. 1985-1990
  11.     All rights reserved.
  12.  
  13.     Some modifications by Erik A. Johnson (johnsone@uxh.cso.uiuc.edu) for
  14.     THINK C (5.0.1).
  15. */
  16.  
  17. enum {
  18.     kFMATEditDLOG = 0,
  19.         kFMATEditFormatItem = 1,
  20.         kFMATEditPositiveItem, kFMATEditNegativeItem, kFMATEditZeroItem,
  21.  
  22.     kFMATStatusStr = 0
  23. };
  24.  
  25. /* _PStrCopy: Copy a Pascal string */
  26. void _PStrCopy( ConstStr255Param src, StringPtr dest )
  27. {
  28.     BlockMove( src, dest, Length( src ) + 1 );
  29. }
  30.  
  31. /* _PStrCat: Concatenate two Pascal strings */
  32. void _PStrCat( ConstStr255Param pend, StringPtr dest )
  33. {
  34.     BlockMove( pend + 1, dest + Length( dest ) + 1, Length( pend ));
  35.     Length( dest ) += Length( pend );
  36. }
  37.  
  38.  
  39. /* ExampleItem: Dialog user item callback to display an example formatted value */
  40. static pascal void ExampleItem( DialogPtr theDialog, short item )
  41. {
  42.     Rect            iRect;
  43.     FontInfo        info;
  44.  
  45.     rFMATHandle        myFMAT;
  46.     Handle            iHandle;
  47.     StringPtr        example;
  48.     long            result;
  49.  
  50.     short            iType;
  51.     short            txFont, txSize;
  52.  
  53.  
  54.     /* Retrieve handle to our FMAT info and lock it down */
  55.     myFMAT = ( rFMATHandle )GetWRefCon( theDialog );
  56.     HLock(( Handle )myFMAT );
  57.  
  58.     /* Determine which string to display */
  59.     switch( item ) {
  60.     case kFMATEditPositiveItem:
  61.         example = ( *myFMAT )->positiveExample;
  62.         break;
  63.  
  64.     case kFMATEditNegativeItem:
  65.         example = ( *myFMAT )->negativeExample;
  66.         break;
  67.  
  68.     case kFMATEditZeroItem:
  69.         example = ( *myFMAT )->zeroExample;
  70.         break;
  71.  
  72.     default:
  73.         goto exit;
  74.     }
  75.  
  76.     /* Erase the item */
  77.     GetDItem( theDialog, item, &iType, &iHandle, &iRect );
  78.     EraseRect( &iRect );
  79.  
  80.     /* Save font/size */
  81.     txFont = theDialog->txFont;
  82.     txSize = theDialog->txSize;
  83.  
  84.     /* Switch to this script's mono-spaced font */
  85.     result = GetScript( Font2Script( txFont ), smScriptMonoFondSize );
  86.     TextFont( HiWord( result ));
  87.     TextSize( LoWord( result ));
  88.  
  89.     /* Use bold red text if the format didn't compile */
  90.     if(( *myFMAT )->curStatus != fFormatOK ) {
  91.         TextFace( bold );
  92.         ForeColor( redColor );
  93.     }
  94.  
  95.     /* Position and draw */
  96.     GetFontInfo( &info );
  97.  
  98.     /* Centered vertically and horizontally within item rectangle */
  99.     MoveTo(( iRect.left + iRect.right - StringWidth( example )) >> 1,
  100.         ( iRect.top + iRect.bottom + info.ascent - info.descent - info.leading ) >> 1 );
  101.     DrawString( example );
  102.  
  103.     /* Restore drawing environment */
  104.     TextFont( txFont );
  105.     TextSize( txSize );
  106.     TextFace( 0 );
  107.     ForeColor( blackColor );
  108.  
  109. exit:
  110.     /* Unlock FMAT info before returning */
  111.     HUnlock(( Handle )myFMAT );
  112. }
  113.  
  114. /* FormatStatusStr: Build text string of FormatStatus error code */
  115. static void FormatStatusStr( FormatStatus status, StringPtr statusStr )
  116. {
  117.     Str255            numString;
  118.  
  119.  
  120.     /* Empty string just in case; do nothing if no error */
  121.     statusStr[ 0 ] = 0;
  122.     if( status == fFormatOK )
  123.         return;
  124.  
  125.     /* Read error message from resource */
  126.     GetIndString( statusStr, ResID( kFMATStatusStr ), status );
  127.     if( statusStr[ 0 ] > 0 )
  128.         return;
  129.  
  130.     /* Unknown error--use "<error n>" */
  131.     _PStrCopy( "\p<error ", statusStr );
  132.     NumToString( status, numString );
  133.     _PStrCat( numString, statusStr );
  134.     _PStrCat( "\p>", statusStr );
  135. }
  136.  
  137. /* FormatExample: Format a single example */
  138. static void FormatExample( double x, NumFormatString *myCanonical, NumberPartsPtr partsTable,
  139.                             StringPtr outString )
  140. {
  141.     FormatStatus    status;
  142.  
  143.  
  144.     /* The funky cast of x here is to overcome a THINK C 5.0 header file mishap */
  145.     status = FormatX2Str( *( extended80 * )&x, myCanonical, partsTable, outString );
  146.  
  147.     /* If there is a formatting error, get the error message */
  148.     if( status != fFormatOK )
  149.         FormatStatusStr( status, outString );
  150. }
  151.  
  152. /* UpdateExamples: Update all examples */
  153. void UpdateExamples( rFMATHandle myFMAT )
  154. {
  155.     Rect            iRect;
  156.     NumFormatString    myCanonical;
  157.     NumberParts        partsTable;
  158.     TripleInt        positions;
  159.     Str255            inString, outString;
  160.  
  161.     DialogPtr        theDialog;
  162.     Ptr                p;
  163.     Handle            iHandle;
  164.  
  165.     FormatStatus    status;
  166.     short            i;
  167.     short            iType;
  168.  
  169.  
  170.     BubbleUp(( Handle )myFMAT );    /* Move our item up in memory */
  171.     HLock(( Handle )myFMAT );        /* Lock it down */
  172.  
  173.     theDialog = ( DialogPtr )( *myFMAT )->w.wind;
  174.     SetPort( theDialog );
  175.  
  176.     /* Zero the canonical format to avoid uninitialized junk */
  177.     for( i = 0, p = ( Ptr )&myCanonical; i < sizeof( myCanonical ); i++ )
  178.         *p++ = 0;
  179.  
  180.     partsTable = ( *myFMAT )->partsTable;
  181.  
  182.     /* Retrieve editable text */
  183.     GetDItem( theDialog, kFMATEditFormatItem, &iType, &iHandle, &iRect );
  184.     GetIText( iHandle, inString );
  185.  
  186.     /* Convert to a canonical format */
  187.     status = Str2Format( inString, &partsTable, &myCanonical );
  188.  
  189.     /* Save in FMAT info */
  190.     ( *myFMAT )->curFormat = myCanonical;
  191.     ( *myFMAT )->curStatus = status;
  192.  
  193.     /* If editable text couldn't be converted, use an error message */
  194.     if( status != fFormatOK ) {
  195. errExit:
  196.         FormatStatusStr( status, ( *myFMAT )->positiveExample );
  197.         ( *myFMAT )->negativeExample[ 0 ] = 0;
  198.         ( *myFMAT )->zeroExample[ 0 ] = 0;
  199.         goto exit;
  200.     }
  201.  
  202.     /* FMAT info's curPositions might become invalidated */
  203.     ( *myFMAT )->curPosValid = FALSE;
  204.  
  205.     /* Convert format back to a string */
  206.     if( Format2Str( &myCanonical, &partsTable, outString, positions ) != fFormatOK )
  207.         goto errExit;
  208.  
  209.     /* If it matches the original, remember curPositions and mark them as valid */
  210.     if( EqualString( inString, outString, TRUE, TRUE )) {
  211.         BlockMove(( Ptr )positions, ( Ptr )( *myFMAT )->curPositions, sizeof( positions ));
  212.         ( *myFMAT )->curPosValid = TRUE;
  213.     }
  214.  
  215.     /* Reformat the three examples */
  216.     FormatExample(  1234.56, &myCanonical, &partsTable, ( *myFMAT )->positiveExample );
  217.     FormatExample( -1234.56, &myCanonical, &partsTable, ( *myFMAT )->negativeExample );
  218.     FormatExample(     0.  , &myCanonical, &partsTable, ( *myFMAT )->zeroExample );
  219.  
  220. exit:
  221.     /* Invalidate the example user items */
  222.     for( i = kFMATEditPositiveItem; i <= kFMATEditZeroItem; i++ ) {
  223.         GetDItem( theDialog, i, &iType, &iHandle, &iRect );
  224.         InvalRect( &iRect );
  225.     }
  226.  
  227.     /* Unlock FMAT info */
  228.     HUnlock(( Handle )myFMAT );
  229. }
  230.  
  231. /* GetNameAndTitle: Fix up the window name and title for our window. */
  232. static void GetNameAndTitle( StringPtr windowTitle, StringPtr windowName,
  233.                           Handle thing )
  234. {
  235.     _PStrCopy( RESOURCE_STRING, windowTitle );
  236.     SetETitle( thing, windowTitle );
  237.     _PStrCopy( windowTitle, windowName );
  238. }
  239.  
  240. /* SetDialogScript: Fix up the dialog to use the given script */
  241. static void SetDialogScript( rFMATHandle myFMAT, short scriptNum )
  242. {
  243.     FontInfo            info;
  244.     NumberParts            partsTable;
  245.  
  246.     DialogPtr            theDialog;
  247.     TEHandle            hTE;
  248.     long                newFont;
  249.     Itl4Handle            itl4;
  250.  
  251.     short                txFont, txSize;
  252.  
  253.  
  254.     /* Make the dialog the current port */
  255.     theDialog = ( DialogPtr )( *myFMAT )->w.wind;
  256.     SetPort( theDialog );
  257.  
  258.     /* Retrieve system font/size for this script */
  259.     newFont = GetScript( scriptNum, smScriptSysFond );
  260.     txFont = LoWord( newFont );
  261.     txSize = 0;
  262.  
  263.     /* Select an editText item to initialize the dialog's TE record */
  264.     SelIText( theDialog, kFMATEditFormatItem, 0, 32767 );
  265.  
  266.     /* Change editText item font */
  267.     hTE = (( DialogPeek )theDialog )->textH;
  268.     ( *hTE )->txFont = txFont;
  269.     ( *hTE )->txSize = txSize;
  270.  
  271.     /* Change the dialog's font */
  272.     TextFont( txFont );
  273.     TextSize( txSize );
  274.  
  275.     /* Update TE record's font info */
  276.     GetFontInfo( &info );
  277.     ( *hTE )->lineHeight = info.ascent + info.descent + info.leading;
  278.     ( *hTE )->fontAscent = info.ascent;
  279.  
  280.     /* Get itl4 record */
  281.     itl4 = ( Itl4Handle )GetResource( 'itl4',
  282.                 GetScript( Font2Script( txFont ), smScriptToken ));
  283.     if( itl4 ) {
  284.  
  285.         /* Retrieve this script's number parts */
  286.         partsTable = *( NumberPartsPtr )(( char * )*itl4 + ( *itl4 )->defPartsOffset );
  287.         ( *myFMAT )->partsTable = partsTable;
  288.  
  289.         /* Rebuild the number parts palette */
  290.         InitNumberPartsPalette(( *myFMAT )->thePalette, &partsTable, txFont );
  291.     }
  292.  
  293.     /* Ensure that the dialog is the current port before returning! */
  294.     SetPort( theDialog );
  295. }
  296.  
  297. /* RevertFormat: Handles the "Revert" command */
  298. static void RevertFormat( rFMATHandle myFMAT )
  299. {
  300.     Rect            iRect;
  301.     Str255            outString;
  302.     NumberParts        partsTable;
  303.  
  304.     DialogPtr        theDialog;
  305.     Handle            iHandle;
  306.  
  307.     short            originalFmtScript;
  308.     short            iType;
  309.     short            start, end;
  310.  
  311.  
  312.     /* Switch to script originally used by format */
  313.     originalFmtScript = ( *myFMAT )->originalFmtScript;
  314.     SetDialogScript( myFMAT, originalFmtScript );
  315.  
  316.     /* Also switch key script if necessary */
  317.     if(( short )GetEnvirons( smKeyScript ) != originalFmtScript )
  318.         KeyScript( originalFmtScript );
  319.  
  320.     /* Restore editable text in dialog */
  321.     theDialog = ( DialogPtr )( *myFMAT )->w.wind;
  322.     _PStrCopy(( *myFMAT )->originalFmtStr, outString );
  323.     GetDItem( theDialog, kFMATEditFormatItem, &iType, &iHandle, &iRect );
  324.     SetIText( iHandle, outString );
  325.     InvalRect( &iRect );
  326.  
  327.     /* Reset selection to positive portion */
  328.     start = ( *myFMAT )->originalPositions[ fPositive ].start - 1;
  329.     end = start + ( *myFMAT )->originalPositions[ fPositive ].length;
  330.     SelIText( theDialog, kFMATEditFormatItem, start, end );
  331.  
  332.     /* Update all examples to reflect reverted edit text */
  333.     UpdateExamples( myFMAT );
  334. }
  335.  
  336. /* EditBirth: Create new Format Editor */
  337. pascal void EditBirth( Handle theResource, ParentHandle dad )
  338. {
  339.     Str255            windowTitle, windowName;
  340.     Rect            iRect;
  341.     NumberParts        partsTable;
  342.     TripleInt        positions;
  343.     Str255            outString;
  344.  
  345.     long            result;
  346.     FMATHandle        thing = ( FMATHandle )theResource;
  347.     rFMATHandle        myFMAT;
  348.     WindowPtr        theWindow;
  349.     Handle            iHandle;
  350.     NumberPartsPaletteHandle    thePalette;
  351.  
  352.     short            item;
  353.     short            iType;
  354.     FormatStatus    status;
  355.     short            txFont;
  356.  
  357.  
  358.     /* If Script Manager isn't available, just use the hex editor */
  359.     if( Gestalt( gestaltScriptMgrVersion, &result ) != noErr || result < 0x0200 ) {
  360.         /* Don't know how to do this yet! */
  361.         return;
  362.     }
  363.  
  364.     /* Prepare window title and request creation of a new window */
  365.     GetNameAndTitle( windowTitle, windowName, ( Handle )thing );
  366.     theWindow = EditorWindSetup( ResID( kFMATEditDLOG ), noColor, 0, 0,
  367.                                 windowTitle, windowName, TRUE, ResEdID(), dad );
  368.  
  369.     /* If we got a new window, then start up the editor */
  370.     if( !theWindow )
  371.         return;
  372.  
  373.      /* Get memory for and handle to our instance record */
  374.     myFMAT = ( rFMATHandle )NewHandle( sizeof( rFMATRec ));
  375.     if( !myFMAT )
  376.         goto errExit1;
  377.  
  378.     SetPort( theWindow );
  379.  
  380.     /* Put information about this incarnation of the editor and the window */
  381.     /* it is serving into our record.                                      */
  382.     /* (always passed around in the handle myFMAT).                        */
  383.  
  384.     _PStrCopy( windowName, ( *myFMAT )->w.name );
  385.     ( *myFMAT )->w.father = dad;
  386.     ( *myFMAT )->w.wind = ( WindowPeek )theWindow;
  387.     ( *myFMAT )->w.rebuild = FALSE;
  388.     ( *myFMAT )->w.resWasntLoaded = !WasItLoaded();
  389.     ( *myFMAT )->w.windowType = editorWindow;
  390.     ( *myFMAT )->w.theResType = RESOURCE_TYPE;
  391.     ( *myFMAT )->w.theResFile = HomeResFile(( Handle )thing );
  392.     ( *myFMAT )->w.codeResID = ResEdID();
  393.     ( *myFMAT )->w.theResToEdit = ( Handle )thing;
  394.  
  395.     /* Let the main program know who is to manage this window by giving it */
  396.     /* both our resource ID number and our instance record handle.         */
  397.     SetWRefCon( theWindow, ( long )myFMAT );
  398.         
  399.     /* Set up any menus,views, etc. for this window here. */
  400.  
  401.     for( item = kFMATEditPositiveItem; item <= kFMATEditZeroItem; item++ ) {
  402.         GetDItem( theWindow, item, &iType, &iHandle, &iRect );
  403.         SetDItem( theWindow, item,  iType, ( Handle )ExampleItem, &iRect );
  404.     }
  405.  
  406.     thePalette = NewNumberPartsPalette( myFMAT );
  407.     if( !thePalette )
  408.         goto errExit1;
  409.     ( *myFMAT )->thePalette = thePalette;
  410.  
  411.     SetDialogScript( myFMAT, ( short )GetEnvirons( smKeyScript ));
  412.  
  413.     ( *myFMAT )->originalFmtStr[ 0 ] = 0;
  414.     ( *myFMAT )->originalFmtScript = Font2Script( theWindow->txFont );
  415.  
  416.     ( *myFMAT )->positiveExample[ 0 ] = 0;
  417.     ( *myFMAT )->negativeExample[ 0 ] = 0;
  418.     ( *myFMAT )->zeroExample[ 0 ] = 0;
  419.  
  420.     /* All done if the resource doesn't yet exist */
  421.     if( GetHandleSize(( Handle )thing ) == 0 )
  422.         return;
  423.  
  424.     /* Convert the format back into editable text */
  425.     partsTable = ( *myFMAT )->partsTable;
  426.     HLock(( Handle )thing );
  427.     status = Format2Str( *thing, &partsTable, outString, positions );
  428.     HUnlock(( Handle )thing );
  429.  
  430.     /* "Revert" it to initialize our structures */
  431.     if( status == fFormatOK ) {
  432.  
  433.         _PStrCopy( outString, ( *myFMAT )->originalFmtStr );
  434.         BlockMove(( Ptr )positions, ( Ptr )( *myFMAT )->originalPositions,
  435.             sizeof( positions ));
  436.  
  437.         RevertFormat( myFMAT );
  438.     }
  439.  
  440.     return;
  441.  
  442. errExit2:
  443.     CloseNumberPartsPalette( thePalette );
  444.  
  445. errExit1:
  446.     CloseWindow( theWindow );
  447.     WindReturn( theWindow );
  448. }
  449.  
  450. /* PickBirth: Not used for editors */
  451. pascal void PickBirth( ResType t, ParentHandle dad )
  452. {
  453. #pragma    unused (t, dad)
  454. }
  455.  
  456. /* DoEvent: The resource editor's event handler */
  457. pascal void DoEvent( EventRecord *evt, ParentHandle object )
  458. {
  459.     Point            where;
  460.  
  461.     rFMATHandle        myFMAT = ( rFMATHandle )object;
  462.     WindowPtr        theWindow, saveFrontWindow, whichWindow;
  463.     WindowPeek        peek;
  464.     DialogPtr        theDialog;
  465.     RgnHandle        updateRgn;
  466.     NumberPartsPaletteHandle    thePalette;
  467.  
  468.     short            item;
  469.     short            saveWindowKind;
  470.     short            scriptNum;
  471.  
  472.  
  473.     /* Handle event passed to us by main program.  Just like a 'real' event    */
  474.     /* loop, except… there is no loop and we don't have to handle as much      */
  475.     /* because the main program will do all the stuff that doesn't apply to us.*/
  476.  
  477.     theWindow = ( WindowPtr )( *myFMAT )->w.wind;
  478.     thePalette = ( *myFMAT )->thePalette;
  479.  
  480.     /*
  481.      *    Since we are a relocatable code resource, our ExampleItem user procs may have
  482.      *    moved. If so, reset them before trying to call the Dialog Manager.
  483.      */
  484.     for( item = kFMATEditPositiveItem; item <= kFMATEditZeroItem; item++ ) {
  485.         Rect iRect;
  486.         Handle iHandle;
  487.         short iType;
  488.  
  489.  
  490.         GetDItem( theWindow, item, &iType, &iHandle, &iRect );
  491.         if( iHandle != ( Handle )ExampleItem )
  492.             SetDItem( theWindow, item, iType, ( Handle )ExampleItem, &iRect );
  493.     }
  494.  
  495.     /* Vector palette window events to palette event handler */
  496.     if(( *thePalette )->fw.wind == ( WindowPtr )evt->message ) {
  497.         if( evt->what == updateEvt ) {
  498.             UpdatePalette( thePalette );
  499.             return;
  500.         }
  501.  
  502.         /* Make a palette activation event look like it's for the dialog */
  503.         if( evt->what == activateEvt )
  504.             evt->message = ( long )theWindow;
  505.     }
  506.  
  507.     switch( evt->what ) {
  508.  
  509.     case updateEvt:
  510.         /*
  511.          *    Since ResEdit helpfully calls BeginUpdate/EndUpdate for me, IsDialogEvent/
  512.          *    DialogSelect get extremely confused about how to update the window. My solution
  513.          *    is to make a copy of the visRgn, call EndUpdate, and call InvalRgn on my visRgn
  514.          *    copy. Then I call IsDialogEvent/DialogSelect. Afterward, I call BeginUpdate
  515.          *    again to make ResEdit happy.
  516.          */
  517.         SetPort( theWindow );
  518.         updateRgn = NewRgn();
  519.         CopyRgn( theWindow->visRgn, updateRgn );
  520.         EndUpdate( theWindow );
  521.         InvalRgn( updateRgn );
  522.         DisposeRgn( updateRgn );
  523.         break;
  524.  
  525.     case keyDown:
  526.         /* Do any key processing here. */
  527.  
  528.         /* Special processing for the tab key */
  529.         if(( evt->message & charCodeMask ) == tabKey ) {
  530.             TEHandle        hTE;
  531.             FormatClass        c;
  532.             short            start, end;
  533.  
  534.  
  535.             /* Totally ignore keypress if current positions aren't valid */
  536.             if( !( *myFMAT )->curPosValid )
  537.                 return;
  538.  
  539.             hTE = (( DialogPeek )theWindow )->textH;
  540.  
  541.             /* Find the current position */
  542.             for( c = fPositive; c <= fZero; c++ ) {
  543.  
  544.                 start = ( *myFMAT )->curPositions[ c ].start - 1;
  545.                 end = start + ( *myFMAT )->curPositions[ c ].length;
  546.                 if(( *hTE )->selStart >= start && ( *hTE )->selStart <= end ) {
  547.  
  548.                     /* Found! Tab backwards if shift-tab */
  549.                     if( evt->modifiers & shiftKey ) {
  550.                         if( --c > fZero )
  551.                             c = fZero;
  552.                     }
  553.  
  554.                     /* Otherwise tab forwards */
  555.                     else {
  556.                         if( ++c > fZero )
  557.                             c = fPositive;
  558.                     }
  559.  
  560.                     /* Move selection */
  561.                     start = ( *myFMAT )->curPositions[ c ].start - 1;
  562.                     end = start + ( *myFMAT )->curPositions[ c ].length;
  563.                     SelIText( theWindow, kFMATEditFormatItem, start, end );
  564.                     break;
  565.                 }
  566.             }
  567.  
  568.             return;
  569.         }
  570.         break;
  571.  
  572.     case mouseDown:
  573.         /* Vector mouse clicks in palette to palette event handler */
  574.         if( FindWindow( evt->where, &whichWindow ) == inContent &&
  575.             ( *thePalette )->fw.wind == whichWindow ) {
  576.             ClickPalette( evt, thePalette );
  577.             return;
  578.         }
  579.         break;
  580.  
  581.     case nullEvent:
  582.         /* Has the keyboard script changed? */
  583.         scriptNum = ( short )GetEnvirons( smKeyScript );
  584.         if( Font2Script( theWindow->txFont ) != scriptNum ) {
  585.  
  586.             /* Switch dialog's script to match */
  587.             SetDialogScript( myFMAT, scriptNum );
  588.  
  589.             /* Convert the current format back into editable text using new script */
  590.             if(( *myFMAT )->curStatus == fFormatOK ) {
  591.                 TripleInt        positions;
  592.                 Str255            outString;
  593.  
  594.                 FormatStatus    status;
  595.  
  596.  
  597.                 HLock(( Handle )myFMAT );
  598.                 status = Format2Str( &( *myFMAT )->curFormat,
  599.                                 &( *myFMAT )->partsTable, outString, positions );
  600.                 HUnlock(( Handle )myFMAT );
  601.         
  602.                 if( status == fFormatOK ) {
  603.                     Rect                iRect;
  604.  
  605.                     Handle                iHandle;
  606.  
  607.                     short                iType, start, end;
  608.  
  609.  
  610.                     /* Remember new positions */
  611.                     BlockMove(( Ptr )positions, ( Ptr )( *myFMAT )->curPositions,
  612.                         sizeof( positions ));
  613.                     ( *myFMAT )->curPosValid = TRUE;
  614.  
  615.                     /* Editable text needs to be updated */
  616.                     GetDItem( theWindow, kFMATEditFormatItem, &iType, &iHandle, &iRect );
  617.                     SetIText( iHandle, outString );
  618.                     InvalRect( &iRect );
  619.  
  620.                     /* Set selection to positive portion */
  621.                     start = positions[ fPositive ].start - 1;
  622.                     end = start + positions[ fPositive ].length;
  623.                     SelIText( theWindow, kFMATEditFormatItem, start, end );
  624.                 }
  625.             }
  626.  
  627.             UpdateExamples( myFMAT );
  628.         }
  629.         break;
  630.     }
  631.  
  632.     /*
  633.      *    Since this is a modeless dialog, I am calling IsDialogEvent/DialogSelect to
  634.      *    handle events. To make this work, I have to temporarily change the windowKind
  635.      *    field of my window to dialogKind.
  636.      */
  637.     peek = ( WindowPeek )theWindow;
  638.     saveWindowKind = peek->windowKind;
  639.     peek->windowKind = dialogKind;
  640.  
  641.     /*
  642.      *    Since I have a floating palette, it is always frontmost. This makes
  643.      *    IsDialogEvent return FALSE for null, activate, mouseDown, and keyDown events.
  644.      *    My solution is to blast my dialog’s pointer into the low memory global
  645.      *    WindowList before calling IsDialogEvent/DialogSelect, and restore WindowList
  646.      *    afterwards. I tried using BringToFront, but when the palette overlapped the
  647.      *    dialog, they were constantly swapping places.
  648.      */
  649.     saveFrontWindow = ( WindowPtr )WindowList;
  650.     if( saveFrontWindow == ( *thePalette )->fw.wind )
  651.         WindowList = peek;
  652.     else
  653.         saveFrontWindow = 0;
  654.  
  655.     /* Process the event */
  656.     if( IsDialogEvent( evt ))
  657.         DialogSelect( evt, &theDialog, &item );
  658.  
  659.     /* Restore WindowList */
  660.     if( saveFrontWindow )
  661.         WindowList = ( WindowPeek )saveFrontWindow;
  662.  
  663.     /* Restore windowKind */
  664.     peek->windowKind = saveWindowKind;
  665.  
  666.     /* Event post-processing */
  667.     switch( evt->what ) {
  668.     case updateEvt:
  669.         /* Call BeginUpdate to balance the EndUpdate that ResEdit will call for us */
  670.         BeginUpdate( theWindow );
  671.         break;
  672.  
  673.     case keyDown:
  674.         /* Update the examples after every key press */
  675.         UpdateExamples( myFMAT );
  676.         break;
  677.     }
  678. }
  679.  
  680. /* DoInfoUpdate: Handles the "Get Resource Info" command */
  681. pascal void DoInfoUpdate( short oldID, short newID, ParentHandle object )
  682. {
  683.     rFMATHandle        myFMAT = ( rFMATHandle )object;
  684.     ParentHandle    father = ( *myFMAT )->w.father;
  685.     Str255            windowTitle, windowName;
  686.  
  687.  
  688.     HLock(( Handle )myFMAT );
  689.  
  690.     /* Since our ID has changed, we need to change our window title */
  691.     GetNameAndTitle( windowTitle, windowName, ( *myFMAT )->w.theResToEdit );
  692.     GetWindowTitle(  windowTitle, windowName, TRUE, father  );
  693.  
  694.     /* Save the new name in my data structure. */
  695.     _PStrCopy( windowName, ( *myFMAT )->w.name );
  696.  
  697.     /* Set the new window title. */
  698.     SetWTitle(( WindowPtr )( *myFMAT )->w.wind, windowTitle );
  699.  
  700.     /* Now, let our father object know that our ID has been changed */
  701.     ( *father )->rebuild = TRUE;            /* Rebuild the picker list. */
  702.     CallInfoUpdate( oldID, newID, ( long )father, ( *father )->wind->windowKind );
  703.  
  704.     HUnlock(( Handle )myFMAT );
  705. }
  706.  
  707. /* IsThisYours: Is this your resource? */
  708. pascal Boolean IsThisYours( Handle thing, ParentHandle object )
  709. {
  710.     return thing == ( *object )->theResToEdit;
  711. }
  712.  
  713. /* FormatChanged: Determine if the format has been significantly changed by editing */
  714. static Boolean FormatChanged( rFMATHandle myFMAT )
  715. {
  716.     Rect                iRect;
  717.     Str255                inString;
  718.  
  719.     Handle                iHandle;
  720.  
  721.     short                iType;
  722.  
  723.  
  724.     /* Get current editable text */
  725.     GetDItem(( DialogPtr )( *myFMAT )->w.wind, kFMATEditFormatItem, &iType, &iHandle, &iRect );
  726.     GetIText( iHandle, inString );
  727.  
  728.     /* Is it what we started with? */
  729.     return !EqualString( inString, ( *myFMAT )->originalFmtStr, TRUE, TRUE );
  730. }
  731.  
  732. /*  Close down the window and get rid of any memory that has been allocated.   */
  733. /*  Returns TRUE if the operation was successful. If notRevert is FALSE the    */
  734. /*  resource isn't released and the data handle isn't disposed (though all the */
  735. /*  handles it contains are disposed).                                         */
  736. static Boolean DoClose( Boolean notRevert, rFMATHandle myFMAT )
  737. {
  738.     Boolean                changed;
  739.     FMATHandle            hFMAT;
  740.  
  741.  
  742.     /* Let parent try to close; cancel if parent aborted */
  743.     PassMenu( fileMenu, closeItem, ( ParentHandle )myFMAT );
  744.     if( WasAborted())
  745.         return FALSE;
  746.  
  747.     /* If the resource was edited, mark it as changed */
  748.     changed = FALSE;
  749.     hFMAT = ( FMATHandle )( *myFMAT )->w.theResToEdit;
  750.     if( !CloseNoSave() && FormatChanged( myFMAT )) {
  751.  
  752.         /* Disallow close if format won't compile */
  753.         if(( *myFMAT )->curStatus != fFormatOK ) {
  754.             SysBeep( 1 );
  755.             Abort();
  756.             return FALSE;
  757.         }
  758.  
  759.         PtrToXHand(( Ptr )&( *myFMAT )->curFormat, ( Handle )hFMAT,
  760.             ( *myFMAT )->curFormat.fLength + 1 );
  761.         ChangedResource(( Handle )hFMAT );
  762.         changed = TRUE;
  763.     }
  764.  
  765.     /* Close it down */
  766.     CloseDialog(( DialogPtr )( *myFMAT )->w.wind );
  767.     WindReturn(( WindowPtr )( *myFMAT )->w.wind ); /*Mark window record as being available */
  768.     SetTheCursor( arrowCursor ); /* Make sure the cursor is arrow cursor */
  769.  
  770.     /* Delete any menus that we added and redraw the menu bar. */
  771.     /* Be sure to dispose of any handles you are done with.    */
  772.     /* Release the resource if we were launched from a picker. */
  773.     if( !changed && notRevert && ( *myFMAT )->w.resWasntLoaded &&
  774.         ( *( *myFMAT )->w.father )->windowType != editorWindow ) {
  775.         ReleaseResource(( Handle )hFMAT );
  776.         /* Let it be free (if it is not changed)! */
  777.     }
  778.  
  779.     CloseNumberPartsPalette(( *myFMAT )->thePalette );
  780.  
  781.     if( notRevert )
  782.         DisposHandle(( Handle )myFMAT );
  783.  
  784.     return TRUE;
  785. }
  786.  
  787. /* DoMenu: Handle menu commands */
  788. pascal void DoMenu( short menu, short item, ParentHandle object )
  789. {
  790.     rFMATHandle        myFMAT = ( rFMATHandle )object;
  791.     Handle            theResource;
  792.     DialogPtr        theDialog;
  793.  
  794.  
  795.     BubbleUp(( Handle )myFMAT );
  796.     HLock(( Handle )myFMAT );
  797.     theDialog = ( DialogPtr )( *myFMAT )->w.wind;
  798.     SetPort( theDialog );        /* Set the port to our window */
  799.  
  800.     theResource = ( *myFMAT )->w.theResToEdit;
  801.  
  802.     /* Again, we handle the menu stuff just as we would in a 'real' application*/
  803.     /* except that we only have to handle those items that apply to our editor.*/
  804.         
  805.     switch( menu ) {
  806.     case fileMenu:
  807.  
  808.         switch( item ) {
  809.         case closeItem:  /* Close our window */
  810.  
  811.             if( DoClose( TRUE, myFMAT )) {
  812.                 return;        /* Return immediately since our resource is gone! */
  813.             }
  814.             break;
  815.  
  816.         case saveItem:    /* Pass the save on to other windows */
  817.             PassMenu( fileMenu, saveItem, ( ParentHandle )myFMAT );
  818.             break;
  819.  
  820.         case printItem:
  821.             /* Cheesy default printing */
  822.             PrintWindow( 0 );
  823.             break;
  824.         }
  825.         break;
  826.  
  827.     case rsrcMenu:
  828.  
  829.         switch( item ) {
  830.  
  831.         case rsrcRevertItem:
  832.             if( !FormatChanged( myFMAT ))
  833.                 break;
  834.  
  835.             if(( *myFMAT )->originalFmtStr[ 0 ] == 0 ) {
  836.  
  837.                 /* The resource was newly added so we need to remove it */
  838.  
  839.                 /* Make sure that the picker list is rebuilt to remove this item */
  840.                 ( *( *myFMAT )->w.father )->rebuild = TRUE;
  841.  
  842.                 /* Close the window */
  843.                 if( DoClose( FALSE, myFMAT )) {
  844.                     RERemoveAnyResource(( *myFMAT )->w.theResFile, theResource );
  845.  
  846.                     /* Dispose the resource itself */
  847.                     DisposHandle(( Handle )myFMAT );
  848.                     return; /* Since the resource is gone. */
  849.                 }
  850.             }
  851.  
  852.             RevertFormat( myFMAT );
  853.             break;
  854.  
  855.         case rsrcGetInfoItem:        /* Show GetInfo window */
  856.             ShowInfo( theResource, ( ParentHandle )myFMAT );
  857.             break;
  858.         }
  859.         break;
  860.  
  861.     case editMenu:            /* Implement the edit menu here    */
  862.         switch( item ) {
  863.         case cutItem:
  864.             DlgCut( theDialog );
  865.             break;
  866.         case copyItem:
  867.             DlgCopy( theDialog );
  868.             break;
  869.         case pasteItem:
  870.             DlgPaste( theDialog );
  871.             break;
  872.         case clearItem:
  873.             DlgDelete( theDialog );
  874.             break;
  875.         }
  876.         break;
  877.     }
  878.  
  879.     HUnlock(( Handle )myFMAT );
  880. }
  881.